package com.taijihuabao.common.interceptor;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.taijihuabao.common.redisconfig.UserLoad;
import com.taijihuabao.modules.entity.UserEntity;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.Objects;
import java.util.Properties;

/**
 * 主键自增
 *
 * @author changhui.tu
 */
@Component
@Intercepts(@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}))
public class MybatisInterceptor implements Interceptor {

    /**
     * 定义实体字段
     */
    private final static String ID_FIELD = "id";
    private final static String CREATOR_TIME_FIELD = "creatorTime";
    private final static String CREATOR_USER_ID_FIELD = "creatorUserId";
    private final static String UPDATE_TIME_FIELD = "lastModifyTime";
    private final static String UPDATE_USER_ID_FIELD = "lastModifyUserId";
    private final static String DELETE_TIME_FIELD = "deleteTime";
    private final static String DELETE_USER_ID_FIELD = "deleteUserId";


    /**
     * 插件运行的代码，它将代替原有的方法
     *
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    @SuppressWarnings("unchecked")
    public Object intercept(Invocation invocation) throws Throwable {
        UserEntity loginUser = UserLoad.getUser();
        //获取参数MappedStatement对象,一个mappedStatement对象对应Mapper配置文件中的一个select/update/insert/delete节点，主要描述的是一条sql语句。
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        //获取sql语句中我们传入的第一个参数
        Object param = invocation.getArgs()[1];
        //获取sql语句类型（SqlCommandType）
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        //插入类型
        if (SqlCommandType.INSERT.equals(sqlCommandType)) {
            //获取我们定义的主键字段并set
            //获取指定字段名的字段(无论私有还是公共)，包括继承/实现的公共的或私有的字段，找不到字段会返回空
            Field id = FieldUtils.getField(param.getClass(), ID_FIELD, true);
            Long value = null;
            if (id != null) {
                id.setAccessible(true);
                //雪花算法生成id并替换sql中id(null)
                if (Objects.isNull(id.get(param))) {
                    Snowflake snowflake = IdUtil.getSnowflake(0, 0);
                    value = snowflake.nextId();
                    id.set(param, value);
                }
            }
            Field crTime = FieldUtils.getField(param.getClass(), CREATOR_TIME_FIELD, true);
            if (crTime != null) {
                crTime.setAccessible(true);
                crTime.set(param, new Date());
            }
            Field crUserId = FieldUtils.getField(param.getClass(), CREATOR_USER_ID_FIELD, true);
            //获取创建人id
            if (crUserId != null) {
                if (loginUser != null) {
                    crUserId.set(param, loginUser.getId());
                } else {
                    crUserId.set(param, value);
                }
                crUserId.setAccessible(true);
            }
        } else if (SqlCommandType.UPDATE.equals(sqlCommandType)) {
            //生成修改时间
            Field updTime = FieldUtils.getField(param.getClass(), UPDATE_TIME_FIELD, true);
            if (updTime != null) {
                updTime.setAccessible(true);
                updTime.set(param, new Date());
            }
            //获取修改人id
            Field updUserId = FieldUtils.getField(param.getClass(), UPDATE_USER_ID_FIELD, true);
            if (updUserId != null) {
                updUserId.setAccessible(true);
                if (loginUser != null) {
                    updUserId.set(param, loginUser.getId());
                }
            }
            //生成删除时间
            Field delTime = FieldUtils.getField(param.getClass(), DELETE_TIME_FIELD, true);
            if (delTime != null) {
                delTime.setAccessible(true);
                delTime.set(param, new Date());
            }
            //获取删除人id
            Field delUserId = FieldUtils.getField(param.getClass(), DELETE_USER_ID_FIELD, true);
            if (delUserId != null) {
                delUserId.setAccessible(true);
                if (loginUser != null) {
                    delUserId.set(param, loginUser.getId());
                }
            }
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        // 返回代理对象或者是原生代理对象,告诉mybatis是不是要进行拦截，如果要拦截，就生成代理对象，不拦截是生成原生对象
        //代理对象写法  Plugin.wrap(target, this);this为拦截器  target代表不代理
        return target instanceof Executor ? (Plugin.wrap(target, this)) : target;
    }

    @Override
    public void setProperties(Properties properties) {
        //可以在Mybatis配置文件中指定一些属性
    }

}
